package com.hub.videobrowsdownload

import android.content.Context
import android.graphics.Bitmap
import android.media.MediaMetadataRetriever
import android.util.Log
import com.forest.download.utils.decrypt
import com.forest.download.utils.handleFormat
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.launch
import java.io.BufferedOutputStream
import java.io.BufferedReader
import java.io.File
import java.io.FileOutputStream
import java.io.FileReader
import java.net.URL
import javax.net.ssl.HttpsURLConnection


class BrowsM3U8Prepare(url: String, webUrl:String) : BrowsVideoPrepare(url, webUrl) {

    override fun prepare(context: Context, title:String?, videoIsWrong: ((Int, Any?) -> Unit)?): BrowsVideoPrepare {
        this.title = title
        stateLiveData.postValue(1)
        isM3U8 = true
        prepareJob = CoroutineScope(Dispatchers.IO).launch {


            try {
                var httpsURLConnection0 = URL(url).openConnection() as HttpsURLConnection
                httpsURLConnection0.setRequestProperty(
                    "User-Agent",
                    "Mozilla/5.0 (Linux; Android 11; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.75 Mobile Safari/537.36"
                );
                httpsURLConnection0.setRequestProperty("Connection", "close");
                httpsURLConnection0.setReadTimeout(26000);
                try {
                    httpsURLConnection0.setRequestProperty(
                        "referer",
                        "https://" + URL(url).host + "/"
                    );
                } catch (e: Exception) {

                }
                httpsURLConnection0.setInstanceFollowRedirects(false);

                httpsURLConnection0.connect();



                val inputStream0 = httpsURLConnection0.inputStream
                val file2 = File(context.cacheDir, "${System.currentTimeMillis()}.m3u8")
                if (!file2.exists()) {
                    file2.createNewFile()
                }
                val fileOutputStream0 = FileOutputStream(file2);
                val arr_b = ByteArray(0x400);
                while (true) {
                    val v2 = inputStream0.read(arr_b);
                    if (v2 != -1) {
                        fileOutputStream0.write(arr_b, 0, v2);
                    } else {
                        inputStream0.close();
                        fileOutputStream0.flush();
                        fileOutputStream0.close();
                        break
                    }
                }

                if (!BrowsM3U8Helper.checkM3U8isGood(file2)) {
                    // 错误的M3U8 格式
                    if (file2.exists()) {
                        file2.delete();
                    }
                    videoIsWrong?.invoke(-1, null)
                } else {
                    if (BrowsM3U8Helper.checkM3U8isSteamInf(file2)) {
                        val parentPath = BrowsM3U8Helper.getUrlParent(url)
                        val fileReader0 = FileReader(file2)
                        val bufferedReader0 = BufferedReader(fileReader0)
                        val m3u8List = arrayListOf<String>()
                        do {
                            val s = bufferedReader0.readLine() ?: break
                            if (s.startsWith("#EXT-X-STREAM-INF")) {
                                if (s.contains("PROGRESSIVE-URI=")) {
                                    try {
                                        val pUrlReg = "PROGRESSIVE-URI=\"(.*?)\"".toRegex()
                                        val pUrl = pUrlReg.find(s)!!.groupValues[1]
                                        if (pUrl.isNotEmpty()) {
                                            var checkUrl = ""
                                            val substring = pUrl.substring(pUrl.lastIndexOf("/"))
                                            if (substring
                                                    .contains("#")
                                            ) {
                                                checkUrl = pUrl.substring(0, pUrl.lastIndexOf("#"))
                                            }
                                            if (!substring.contains(".")) {
                                                checkUrl += ".mp4"
                                            }
                                            m3u8List.add(getHttpRealTsUrl(checkUrl, parentPath))
                                            Log.i("知道夜生活", checkUrl)
                                            continue
                                        }
                                    } catch (e: Exception) {
                                        e.printStackTrace()
                                    }
                                }

                            }
                            if (!s.startsWith("#")) {
                                val pppp = if (parentPath.endsWith("/") || s.startsWith("/")) {
                                    ""
                                }else{
                                    "/"
                                }
                                if (s.startsWith("http://") || s.startsWith("https://")){
                                    if (!m3u8List.contains(s)){
                                        m3u8List.add(s)
                                    }
                                }else{
                                    val sss = "${parentPath}${pppp}${s}"
                                    if (!m3u8List.contains(sss)){
                                        m3u8List.add(sss)
                                    }
                                }
                            }
                        } while (true)

                        videoIsWrong?.invoke(-2, m3u8List)
                    }else{
                        videoIsWrong?.invoke(1, this@BrowsM3U8Prepare)
                        // 正常的 M3U8 格式
                        var duration = 0.0
                        val fileReader0 = FileReader(file2)
                        val bufferedReader0 = BufferedReader(fileReader0)
                        val tsList = arrayListOf<String>()
                        var byteLength = 0L

                        val parentPath = BrowsM3U8Helper.getUrlParent(url)
                        var KEY_URI = ""
                        var iv: String = ""
                        do {
                            val s = bufferedReader0.readLine() ?: break

                            // 时长标志
                            val prefix = "#EXTINF:"
                            if (s.startsWith("#EXT-X-KEY:")){
                                if (s.contains("IV")) {
                                    val ivRegex = "IV=0x(.*?)".toRegex()
                                    ivRegex.find(s)?.let { iv = it.groupValues[1].trim() }
                                    if (iv.isEmpty()) {
                                        val startIndex = s.lastIndexOf("IV=0x") + 5
                                        iv = s.substring(startIndex).trim()
                                    }

                                }
                                try {
                                    val keyRegex = "URI=\"(.*?)\"".toRegex()
                                    val keyUrl = keyRegex.find(s)!!.groupValues[1]
                                    KEY_URI =  getHttpRealTsUrl(keyUrl, parentPath)
                                } catch (e: Exception) {
                                    e.printStackTrace()
                                }

                            }else if (s.startsWith(prefix)) {
                                var d =
                                    (s.replace(prefix, "").replace(",", "").trim().toDoubleOrNull())
                                        ?: 0.0
                                duration += d
                            } else {
                                if (!s.startsWith("#")) {
                                    tsList.add(s.trim())
                                }else if (s.startsWith("#EXT-X-BYTERANGE:")){
                                    var replace = s.replace("#EXT-X-BYTERANGE:", "")
                                    val indexOf = replace.indexOf("@")
                                    if (indexOf != -1) {
                                       replace =  replace.substring(0, indexOf)
                                    }
                                    var range = replace.trim().toLongOrNull()?:0L
                                    byteLength += range
                                }

                            }

                        } while (true)


                        videoDuration.postValue(duration)

                        val thumbFile =
                            File(BrowsM3U8Helper.getThumbDir(context), "${System.currentTimeMillis()}_thumb.jpg")
                        var contextLength = 0L
                        if (byteLength > 0) {
                            contextLength = byteLength
                            videoLength.postValue(byteLength)
                            val thumbJOb = async {
                                try {
                                    getTsThumb(  context, getHttpRealTsUrl(tsList.random(), parentPath),thumbFile, tsList.size, parentPath, KEY_URI, iv)
                                } catch (e: Exception) {
                                }
                            }
                            thumbJOb.await()
                            stateLiveData.postValue(2)
                        }else{


                            var centerIndex = if (tsList.size > 3) 3 else tsList.size - 1
                            if (centerIndex < 0) {
                                centerIndex = 0
                            }


                            val totalTsSize = tsList.size
                            val urlsPerCoroutine = 5
                            val iterations =
                                kotlin.math.ceil(totalTsSize.toDouble() / urlsPerCoroutine).toInt()
                            val thumbJOb = async {
                                try {
                                    getTsThumb( context,   getHttpRealTsUrl(tsList.random(), parentPath),thumbFile, tsList.size, parentPath, KEY_URI, iv)
                                } catch (e: Exception) {
                                }
                            }
                            thumbJOb.await()
                            stateLiveData.postValue(2)
                            if (!BrowsM3U8Helper.useM3U8FakeContentLength) {
                                repeat(iterations) {
                                    val jobs = List(urlsPerCoroutine) { i ->
                                        async {
                                            var contentLengthLong = 0L
                                            val index = it * urlsPerCoroutine + i
                                            val url = try {
                                                tsList[index]
                                            } catch (e: Exception) {
                                                null
                                            }
                                            if (!url.isNullOrEmpty()) {
                                                // Content-Length
                                                val tsUrl =
                                                    getHttpRealTsUrl(url, parentPath)

                                                var httpConnect =
                                                    URL(tsUrl).openConnection() as HttpsURLConnection
                                                httpConnect.setRequestProperty(
                                                    "User-Agent",
                                                    "Mozilla/5.0 (Linux; Android 11; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.75 Mobile Safari/537.36"
                                                );
                                                httpConnect.setRequestProperty("Connection", "close");
                                                httpConnect.setReadTimeout(26000);
                                                try {
                                                    httpConnect.setRequestProperty(
                                                        "referer",
                                                        "https://" + URL(tsUrl).host + "/"
                                                    );
                                                } catch (e: Exception) {

                                                }
                                                httpConnect.setInstanceFollowRedirects(false);
                                                httpConnect.setRequestMethod("HEAD");
                                                httpConnect.connect();

                                                contentLengthLong = httpConnect.contentLengthLong

                                            }
                                            contentLengthLong
                                        }
                                    }
                                    jobs.awaitAll().forEach {
                                        contextLength += it
                                    }
                                }
                                videoLength.postValue(contextLength)
                            }

                        }



                    }


                }
            } catch (e: Exception) {
                videoIsWrong?.invoke(-3, null)
            }
            stateLiveData.postValue(2)
        }
        return this
    }

    private fun getHttpRealTsUrl(url: String, parentPath: String): String {
        val tsUrl =
            if (url.startsWith("http://") || url.startsWith("https://")) {
                url
            } else {
                var sf = "/"
                if (parentPath.endsWith("/") || url.startsWith("/")) {
                    sf = ""
                }
                parentPath + sf + url
            }
        return tsUrl
    }

    private fun getTsThumb(context:Context,
        tsUrl: String,
        thumbFile: File,tsListSize:Int, parentPath: String, KEY_URI:String, iv:String
    ) {
        if (KEY_URI.isNotEmpty()) {
            var success: Boolean = false
            val arr_b_key = ByteArray(16)
            try {
                success = false
                var httpsURLConnection0 = URL(KEY_URI).openConnection() as HttpsURLConnection
                httpsURLConnection0.setRequestProperty(
                    "User-Agent",
                    "Mozilla/5.0 (Linux; Android 11; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.75 Mobile Safari/537.36"
                );
                httpsURLConnection0.setRequestProperty("Connection", "close");
                httpsURLConnection0.setReadTimeout(26000);
                try {
                    httpsURLConnection0.setRequestProperty(
                        "referer",
                        "https://" + URL(KEY_URI).host + "/"
                    );
                } catch (e: Exception) {

                }
                httpsURLConnection0.setInstanceFollowRedirects(false);

                httpsURLConnection0.connect();

                val v = httpsURLConnection0.getResponseCode()
                if (v in 200..299) {
                    if (httpsURLConnection0.contentLengthLong == 16L) {
                        val inputStream0 = httpsURLConnection0.inputStream
                        val arr_b1 = ByteArray(16)
                        var v1 = 0
                        while (true) {
                            val v2 = inputStream0.read(arr_b1)
                            if (v2 == -1) {
                                break
                            }
                            System.arraycopy(arr_b1, 0, arr_b_key, v1, v2)
                            v1 += v2
                        }
                        inputStream0.close()
                        httpsURLConnection0.disconnect()

                        success = true
                    }else{

                        httpsURLConnection0.disconnect()
                    }
                }
            } catch (e: Exception) {
                e.printStackTrace()
            }
            if (success){
                try {
                    var httpsURLConnection0 = URL(tsUrl).openConnection() as HttpsURLConnection
                    httpsURLConnection0.setRequestProperty(
                        "User-Agent",
                        "Mozilla/5.0 (Linux; Android 11; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.75 Mobile Safari/537.36"
                    );
                    httpsURLConnection0.setRequestProperty("Connection", "close");
                    httpsURLConnection0.setReadTimeout(26000);
                    try {
                        httpsURLConnection0.setRequestProperty(
                            "referer",
                            "https://" + URL(tsUrl).host + "/"
                        );
                    } catch (e: Exception) {

                    }
                    httpsURLConnection0.setInstanceFollowRedirects(false);

                    httpsURLConnection0.connect();


                    val inputStream0 = httpsURLConnection0.inputStream
                    val file2 = File(context.cacheDir, "${System.currentTimeMillis()}.ts")
                    if (!file2.exists()) {
                        file2.createNewFile()
                    }
                    val fileOutputStream0 = FileOutputStream(file2);
                    val arr_b = ByteArray(0x400);
                    while (true) {
                        val v2 = inputStream0.read(arr_b);
                        if (v2 != -1) {
                            fileOutputStream0.write(arr_b, 0, v2);
                        } else {
                            inputStream0.close();
                            fileOutputStream0.flush();
                            fileOutputStream0.close();
                            break
                        }
                    }

                    httpsURLConnection0.disconnect()
                    if (file2.length() > 0) {

                        val dFile = File(context.cacheDir, "${System.currentTimeMillis()}.ts")
                        BufferedOutputStream(dFile.outputStream()).use { output ->
                            file2.handleFormat()
                            val bytes =
                                file2.readBytes().decrypt(arr_b_key, iv)

                            output.write(bytes)

                        }

                        var width1 = 0
                        var height1 = 0
                        try {
                            val retriever = MediaMetadataRetriever()

                            retriever.setDataSource(dFile.absolutePath)

                            try {
                                width1 =
                                    retriever.extractMetadata(
                                        MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH
                                    )!!
                                        .toInt()
                                height1 =
                                    retriever.extractMetadata(
                                        MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT
                                    )!!
                                        .toInt()
                                videoHeight.postValue(height1)
                                videoWidth.postValue(width1)
                            } catch (e: Exception) {
                            }

                            val frame = retriever.getFrameAtTime(0)

                            FileOutputStream(thumbFile).use { out ->
                                frame!!.compress(
                                    Bitmap.CompressFormat.JPEG,
                                    90,
                                    out
                                )
                            }
                            if (thumbFile.length() > 0) {
                                videoHeight.postValue(height1)
                                videoWidth.postValue(width1)
                                thumbPath.postValue(thumbFile.absolutePath)
                                if (downloadWrapper.value != null) {
                                    changeThumbToDownloadFileDir(context)
                                }
                            }
                        } catch (e: Throwable) {
                            e.printStackTrace()
                        }
                    }
                } catch (e: Exception) {
                    e.printStackTrace()
                }
            }
        }else{

            var width1 = 0
            var height1 = 0
            try {
                val retriever = MediaMetadataRetriever()
                val hashMap0 = hashMapOf<String, String>()
                hashMap0["Referer"] =
                    "https://" + URL(tsUrl).host + "/"
                retriever.setDataSource(tsUrl, hashMap0)

                try {
                    width1 =
                        retriever.extractMetadata(
                            MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH
                        )!!
                            .toInt()
                    height1 =
                        retriever.extractMetadata(
                            MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT
                        )!!
                            .toInt()
                    videoHeight.postValue(height1)
                    videoWidth.postValue(width1)
                } catch (e: Exception) {
                }

                val frame = retriever.getFrameAtTime(0)

                FileOutputStream(thumbFile).use { out ->
                    frame!!.compress(
                        Bitmap.CompressFormat.JPEG,
                        90,
                        out
                    )
                }
                if (thumbFile.length() > 0) {
                    videoHeight.postValue(height1)
                    videoWidth.postValue(width1)
                    thumbPath.postValue(thumbFile.absolutePath)
                    if (downloadWrapper.value != null) {
                        changeThumbToDownloadFileDir(context)
                    }
                }
            } catch (e: Throwable) {
                e.printStackTrace()
            }
        }
        if (BrowsM3U8Helper.useM3U8FakeContentLength && videoLength.value == null || videoLength.value == 0L) {
            try {
                var contentLengthLong = 0L
                var url =tsUrl
                if (url.isNotEmpty()) {
                    // Content-Length
                    url =
                        getHttpRealTsUrl(url, parentPath)

                    var httpConnect =
                        URL(url).openConnection() as HttpsURLConnection
                    httpConnect.setRequestProperty(
                        "User-Agent",
                        "Mozilla/5.0 (Linux; Android 11; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.75 Mobile Safari/537.36"
                    );
                    httpConnect.setRequestProperty("Connection", "close");
                    httpConnect.setReadTimeout(26000);
                    try {
                        httpConnect.setRequestProperty(
                            "referer",
                            "https://" + URL(url).host + "/"
                        );
                    } catch (e: Exception) {

                    }
                    httpConnect.setInstanceFollowRedirects(false);
                    httpConnect.setRequestMethod("HEAD");
                    httpConnect.connect();

                    contentLengthLong = httpConnect.contentLengthLong

                }
                videoLength.postValue(contentLengthLong * tsListSize)
            }catch (e:Exception){
                e.printStackTrace()
            }
        }

    }
}